// Spheregraph.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "Spheregraph.h"

#include "GraphicsLayer.h"
#include "Surface.h"

#include <stdio.h>


#define MAX_LOADSTRING 100
#define TIMER_ID 1
#define TIMER_MS (1000 / 60)

// Global Variables:
HINSTANCE	hInst;								// current instance
TCHAR		szTitle[MAX_LOADSTRING];			// The title bar text
TCHAR		szWindowClass[MAX_LOADSTRING];		// the main window class name
int			g_iTechniqueType = 1;
int			MouseX = 0;
int			MouseY = 0;
bool		ctrl			= false;
bool		shift			= false;
bool		render			= false;
bool		drawSolid		= true;
bool		drawWire		= true;
bool		drawGrass		= false;
bool		surfaceNormals	= true;
float		thetaA = 0.0;
float		thetaB = 2.0;
float		phiA = 0.0;
float		phiB = 1.0;
float		plX1 = -2.0;
float		plX2 = 2.0;
float		plY1 = -2.0;
float		plY2 = 2.0;
float		plZ1 = -2.0;
float		plZ2 = 2.0;
			
			
CSurface	*g_Surface[2]={NULL,NULL};
CSurface	*g_PlaneXY=NULL;
CSurface	*g_PlaneXZ=NULL;
CSurface	*g_PlaneYZ=NULL;
			
			
HWND		g_hWnd, g_hwndChild, equation, plot, thetaLimitA, thetaLimitB, phiLimitA, phiLimitB, solid, grass, wiref ;
HWND		orthographic, perspective, surface, triangle, planeX1, planeX2, planeY1, planeY2, planeZ1, planeZ2;

std::ifstream hlsl_file;
std::ofstream hlsl_temp;

std::string part[3];


// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
ATOM				MyRegisterClassChild(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);

LRESULT CALLBACK	MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK	ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

BOOL                InitDevice(HWND hWnd);
void                Render();
void				ImageCapture(HWND hWnd);//add to capture images
void				CreateObjects();
void				ResetView();


int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	MSG msg={0};
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_SPHEREGRAPH, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);
	MyRegisterClassChild(hInstance);

	//Load template file
	int i=0;
	hlsl_file.open( "D3D11Plot_template.hlsl" );
	if( hlsl_file.is_open() )
	{
		char line[512];
		while( !hlsl_file.eof() )
		{
			hlsl_file.getline(line,512);
			if( std::strcmp("## EQ ##",line) == 0 || std::strcmp("## DERIVATIVES ##",line) == 0 )
			{
				i++;
				continue;
			}
			part[i].append(line);
			part[i].append("\n");
		}
		hlsl_file.close();
	}
	//else display error!

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SPHEREGRAPH));

	// Force Init
	MainWndProc(g_hWnd, WM_COMMAND, 98307, NULL);
	
	while( WM_QUIT != msg.message )
	{
	    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
	    {
	        TranslateMessage( &msg );
	        DispatchMessage( &msg );
	    }
	    else
	    {
			if(render)
				Render();
	    }
	}
	
	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= MainWndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SPHEREGRAPH));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_SPHEREGRAPH);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

ATOM MyRegisterClassChild(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
	wcex.lpfnWndProc	= ChildWndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SPHEREGRAPH));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(ID_PLOT);
	wcex.lpszClassName	= L"Child";
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
	
	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	HWND hWnd;
	
	hInst = hInstance; // Store instance handle in our global variable
	
	hWnd = CreateWindow(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,
						20, 20, 1000, 600, NULL, NULL, hInstance, NULL);
	
	g_hWnd = hWnd;
	if (!hWnd)
	{
		return FALSE;
	}
	
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	
	return TRUE;
}

BOOL CALLBACK EnumChildProc(HWND g_g_hwndChild, LPARAM lParam) 
{ 
	LPRECT rcParent; 
	int idChild; 
	
	idChild = GetWindowLong(g_hwndChild, GWL_ID); 
	if (idChild == ID_PLOT)
	{
		// Size and position the child window.  
		rcParent = (LPRECT) lParam; 

		MoveWindow(g_hwndChild, 10, 10, rcParent->right / 2+100, rcParent->bottom-20, TRUE);
	}
	ShowWindow(g_hwndChild, SW_SHOW); 
	
	return TRUE;
}


LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_KEYUP:
		{
			switch(wParam)
			{	
				case '1':
					g_iTechniqueType = 1;
					break;
				case '2':
					g_iTechniqueType = 2;
					break;
				case '3':
					g_iTechniqueType = 3;
					break;
				case '4':
					g_iTechniqueType = 4;
					break;
				case '5':
					g_iTechniqueType = 5;
					break;
				case '6':
					g_iTechniqueType = 6;
					break;
				case 67:
					ImageCapture(hWnd);	//using "c"
				break;
			}
			if( wParam == VK_CONTROL )
				ctrl = false;
			if( wParam == VK_SHIFT )
				shift = false;
		}break;

		case WM_KEYDOWN:
		{
			if( wParam == VK_CONTROL )
				ctrl = true;
			if( wParam == VK_SHIFT )
				shift = true;
		}break;
		
		case WM_LBUTTONDOWN:
		{
			MouseX=(short)LOWORD(lParam);
			MouseY=(short)HIWORD(lParam);
		}break;
		
		case WM_MOUSEWHEEL:
		{
			D3DXMATRIX mtxView;
			D3DXVECTOR3 vecEye, vecAt, vecUp;
			Graphics()->GetVecEye( vecEye );
			Graphics()->GetVecAt( vecAt );
			Graphics()->GetVecUp( vecUp );

			int move = (short)HIWORD(wParam);
			
			float t, p, r;
				
			r = sqrt(pow(vecEye.x,2)+pow(vecEye.y,2)+pow(vecEye.z,2));

			t = acos(vecEye.y/r);
			p = atan2(vecEye.x,vecEye.z);
			
			r -= (move)*0.002;

			vecEye.z = r*cos(p)*sin(t);
			vecEye.x = r*sin(p)*sin(t);
			vecEye.y = r*cos(t);
				
			Graphics()->SetVecEye( vecEye );
			Graphics()->SetVecAt( vecAt );
			Graphics()->SetVecUp( vecUp );
			D3DXMatrixLookAtLH(&mtxView, &vecEye, &vecAt, &vecUp);
			Graphics()->SetViewMtx(mtxView);
			Graphics()->UpdateMatrices();

		}break;

		case WM_MOUSEMOVE:
		{
			
			// Check to see if the left button is held down:
			bool leftButtonDown=wParam & MK_LBUTTON;
			if( leftButtonDown )
			{
				SetFocus(hWnd);

				int x=(short)LOWORD(lParam);
				int y=(short)HIWORD(lParam);
				
				D3DXMATRIX mtxView;
				D3DXVECTOR3 vecEye, vecAt, vecUp;
				Graphics()->GetVecEye( vecEye );
				Graphics()->GetVecAt( vecAt );
				Graphics()->GetVecUp( vecUp );

				if( shift )
				{
					g_Surface[0]->Translate(0.0,0.0,-(MouseY-y)*0.01);
					g_Surface[1]->Translate(0.0,0.0,-(MouseY-y)*0.01);
					g_PlaneXY   ->Translate(0.0,0.0,-(MouseY-y)*0.01);
					g_PlaneXZ   ->Translate(0.0,0.0,-(MouseY-y)*0.01);
					g_PlaneYZ   ->Translate(0.0,0.0,-(MouseY-y)*0.01);
				}
				else if( ctrl )
				{
					g_Surface[0]->Translate((MouseX-x)*0.01,(MouseY-y)*0.01,0.0);
					g_Surface[1]->Translate((MouseX-x)*0.01,(MouseY-y)*0.01,0.0);
					g_PlaneXY   ->Translate((MouseX-x)*0.01,(MouseY-y)*0.01,0.0);
					g_PlaneXZ   ->Translate((MouseX-x)*0.01,(MouseY-y)*0.01,0.0);
					g_PlaneYZ   ->Translate((MouseX-x)*0.01,(MouseY-y)*0.01,0.0);
				}
				else
				{
					g_Surface[0]->Rotate(0.0,-(MouseY-y)*0.05,(MouseX-x)*0.05);
					g_Surface[1]->Rotate(0.0,-(MouseY-y)*0.05,(MouseX-x)*0.05);
					g_PlaneXY   ->Rotate(0.0,-(MouseY-y)*0.05,(MouseX-x)*0.05);
					g_PlaneXZ   ->Rotate(0.0,-(MouseY-y)*0.05,(MouseX-x)*0.05);
					g_PlaneYZ   ->Rotate(0.0,-(MouseY-y)*0.05,(MouseX-x)*0.05);
				}
				Graphics()->SetVecEye( vecEye );
				Graphics()->SetVecAt( vecAt );
				Graphics()->SetVecUp( vecUp );
				D3DXMatrixLookAtLH(&mtxView, &vecEye, &vecAt, &vecUp);
				Graphics()->SetViewMtx(mtxView);
				Graphics()->UpdateMatrices();

				MouseX = x;
				MouseY = y;
			}
		}break;

		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	RECT rcClient;

	switch (message)
	{
		case WM_MOUSEMOVE:
		{
			bool leftButtonDown=wParam & MK_LBUTTON;
			if( leftButtonDown )
				SetFocus(hWnd);
		}break;
		case WM_KEYUP:
		{
			switch(wParam)
			{	
				case '1':
					g_iTechniqueType = 1;
					break;
				case '2':
					g_iTechniqueType = 2;
					break;
				case '3':
					g_iTechniqueType = 3;
					break;
				case '4':
					g_iTechniqueType = 4;
					break;
				case '5':
					g_iTechniqueType = 5;
					break;
				case '6':
					g_iTechniqueType = 6;
					break;
				case 67:
					ImageCapture(hWnd);	//using "c"
				break;
			}
			if( wParam == VK_CONTROL )
				ctrl = false;
			if( wParam == VK_SHIFT )
				shift = false;
		}
		break;

		case WM_KEYDOWN:
		{
			if( wParam == VK_CONTROL )
				ctrl = true;
			if( wParam == VK_SHIFT )
				shift = true;
		}break;

		case WM_COMMAND:
		{
			wmId    = LOWORD(wParam);
			wmEvent = HIWORD(wParam);
			// Parse the menu selections:
			switch (wmId)
			{
				case IDC_PERSPECTIVE_BUTTON:
				{
					ResetView();
					Graphics()->CreatePerspectiveCamera();
				}break;
				
				case IDC_ORTHOGRAPHIC_BUTTON:
				{
					ResetView();
					Graphics()->CreateOrthographicCamera();
				}break;

				case IDC_PLOT_BUTTON:
				{
					int i=0;
					hlsl_temp.open( "D3D11Plot_tmp.hlsl" );
					hlsl_temp.clear();
					if( hlsl_temp.is_open() )
					{
						TCHAR buffer[256];
						char buffer2[256];
						std::string tmp;
						int pos;

						SendMessage(equation,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);

						hlsl_temp << part[0];

						hlsl_temp << "r = " << buffer2 << ";" << std::endl ;

						hlsl_temp << part[1];

						tmp.erase();tmp.assign(buffer2);
						pos = tmp.find("t");
						while( pos != std::string::npos )
						{	
							tmp.replace(pos,1,"(t+h)");
							pos = tmp.find("t",pos+2);
						}
						hlsl_temp << "f11 = " << tmp << ";" << std::endl;

						tmp.erase();tmp.assign(buffer2);
						pos = tmp.find("t");
						while( pos != std::string::npos )
						{	
							tmp.replace(pos,1,"(t-h)");
							pos = tmp.find("t",pos+2);
						}
						hlsl_temp << "f12 = " << tmp << ";" << std::endl;

						tmp.erase();tmp.assign(buffer2);
						pos = tmp.find("p");
						while( pos != std::string::npos )
						{	
							tmp.replace(pos,1,"(p+h)");
							pos = tmp.find("p",pos+2);
						}
						hlsl_temp << "f21 = " << tmp << ";" << std::endl;

						tmp.erase();tmp.assign(buffer2);
						pos = tmp.find("p");
						while( pos != std::string::npos )
						{	
							tmp.replace(pos,1,"(p-h)");
							pos = tmp.find("p",pos+2);
						}
						hlsl_temp << "f22 = " << tmp << ";" << std::endl;
						
						//hlsl_temp << "dr = (" << buffer2 << ")/abs(" << buffer2 << ");" << std::endl;
						hlsl_temp << "dr = -1.0;" << std::endl;
																	
						hlsl_temp << part[2] << std::endl ;
						
						hlsl_temp.close();

						//Parametros de theta y phi

						
						SendMessage(thetaLimitA,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						thetaA = atof(buffer2);

						SendMessage(thetaLimitB,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						thetaB = atof(buffer2);

						/*if(thetaA<0.0)
							thetaA = 0.0;
						if(thetaA>2.0)
							thetaA = 2.0;
						if(thetaB<0.0)
							thetaB = 0.0;
						if(thetaB>2.0)
							thetaB = 2.0;
						if(thetaA>thetaB)
						{
							float temp = thetaA;
							thetaA=thetaB;
							thetaB=temp;
						}*/


						SendMessage(phiLimitA,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						phiA = atof(buffer2);

						SendMessage(phiLimitB,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						phiB = atof(buffer2);

						/*if(phiA<0.0)
							phiA = 0.0;
						if(phiA>1.0)
							phiA = 1.0;
						if(phiB<0.0)
							phiB = 0.0;
						if(phiB>1.0)
							phiB = 1.0;
						if(phiA>phiB)
						{
							float temp = phiA;
							phiA=phiB;
							phiB=temp;
						}*/

						//Parametros de los planos
						
						SendMessage(planeX1,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						plX1 = atof(buffer2);

						SendMessage(planeX2,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						plX2 = atof(buffer2);

						SendMessage(planeY1,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						plY1 = atof(buffer2);

						SendMessage(planeY2,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						plY2 = atof(buffer2);

						SendMessage(planeZ1,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						plZ1 = atof(buffer2);

						SendMessage(planeZ2,WM_GETTEXT,sizeof(buffer)/sizeof(buffer[0]),reinterpret_cast<LPARAM>(buffer));
						wcstombs(buffer2,buffer,256);
						plZ2 = atof(buffer2);


						if(SendMessage(solid,BM_GETCHECK,0,0) == BST_UNCHECKED)
							drawSolid = false;
						else
							drawSolid = true;
						if(SendMessage(wiref,BM_GETCHECK,0,0) == BST_UNCHECKED)
							drawWire = false;
						else
							drawWire = true;
						if(SendMessage(grass,BM_GETCHECK,0,0) == BST_UNCHECKED)
							drawGrass = false;
						else
							drawGrass = true;
						if(SendMessage(surface,BM_GETCHECK,0,0) == BST_UNCHECKED)
							surfaceNormals = false;
						else
							surfaceNormals = true;

						CreateObjects();

						Graphics()->CreateShader();
						render = true;
					}
				}break;
				case ID_FILE_INITD3D:
				{
					if (Graphics())
					{
						MessageBox(hWnd, TEXT("D3D11 Device already initialized"), 
						TEXT("Init Skipped"), MB_OK | MB_ICONWARNING);
					}
					else
					{
						if (InitDevice(g_hwndChild) == FALSE)
						{
							MessageBox(hWnd, TEXT("Failed to Initialize D3D11"), TEXT("Init Failure"), MB_OK | MB_ICONERROR);
						}
					}
				}break;

				case ID_FILE_CLOSED3D:
				{
					KillTimer(hWnd, TIMER_ID);

					InvalidateRect(hWnd, NULL, TRUE);
				}break;

				case IDM_ABOUT:
				{
					DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
				}break;

				case IDM_EXIT:
				{
					DestroyWindow(hWnd);
				}break;

				default:
					return DefWindowProc(hWnd, message, wParam, lParam);
			}
		}break;

		case WM_PAINT:
		{
			if (Graphics())
			{
				if(render)
					Render();
			}
			else
			{
				hdc = BeginPaint(hWnd, &ps);
				EndPaint(hWnd, &ps);
			}
		}break;

		case WM_SIZE:
		{
			GetClientRect(hWnd, &rcClient); 
			EnumChildWindows(hWnd, EnumChildProc, (LPARAM) &rcClient); 
		}break;

		case WM_CREATE:
		{
			GetClientRect(hWnd, &rcClient); 

			g_hwndChild = CreateWindowEx( 0, L"Child", (LPCTSTR) NULL, WS_CHILD | WS_BORDER | WS_VISIBLE , 0,0,0,0, hWnd, (HMENU) ID_PLOT, hInst, NULL);

			CreateWindowEx(	0, L"STATIC", L"Equation:", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 20, 350, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);

			CreateWindowEx(	0, L"STATIC", L"r = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 50, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			equation = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+25, 50, 325, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);

			CreateWindowEx(	0, L"STATIC", L"Theta:", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 80, 350, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			
			CreateWindowEx(	0, L"STATIC", L"A = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 110, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			thetaLimitA = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"0.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+145, 110, 80, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"PI", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+110, 110, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"B = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+45+100, 110, 22, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			thetaLimitB = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100, 110, 80, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"PI", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100+80, 110, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			
			CreateWindowEx(	0, L"STATIC", L"Phi:", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 140, 350, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);

			CreateWindowEx(	0, L"STATIC", L"A = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 170, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			phiLimitA = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"0.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+145, 170, 80, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"PI", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+110, 170, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"B = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+45+100, 170, 22, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			phiLimitB = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"1.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100, 170, 80, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"PI", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100+80, 170, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);

			CreateWindowEx(	0, L"STATIC", L"Draw Options:", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 200, 350, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			solid = CreateWindowEx( 0, L"BUTTON", L"Solid", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, rcClient.right/2+120, 230, 100, 20, hWnd, (HMENU)IDC_SOLID_BUTTON, hInst, NULL);
			wiref = CreateWindowEx( 0, L"BUTTON", L"Wire Frame", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, rcClient.right/2+120+100, 230, 100, 20, hWnd, (HMENU)IDC_WIRE_BUTTON, hInst, NULL);
			grass = CreateWindowEx( 0, L"BUTTON", L"Grass", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, rcClient.right/2+120+100+120, 230, 100, 20, hWnd, (HMENU)IDC_GRASS_BUTTON, hInst, NULL);
			SendMessage(solid,BM_SETCHECK,BST_CHECKED,NULL);
			SendMessage(wiref,BM_SETCHECK,BST_CHECKED,NULL);
			SendMessage(grass,BST_UNCHECKED,BST_CHECKED,NULL);

			CreateWindowEx( 0, L"BUTTON", L"Normals:", WS_CHILD|WS_VISIBLE|BS_GROUPBOX, rcClient.right/2+120, 260, 300, 50, hWnd, (HMENU)IDC_SOLID_BUTTON, hInst, NULL);
			surface = CreateWindowEx( 0, L"BUTTON", L"Surface", WS_CHILD|WS_VISIBLE|WS_GROUP|BS_AUTORADIOBUTTON, rcClient.right/2+120+10, 280, 100, 20, hWnd, (HMENU)IDC_SURFACE_BUTTON, hInst, NULL);
			triangle = CreateWindowEx( 0, L"BUTTON", L"Triangle", WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, rcClient.right/2+120+45+100, 280, 100, 20, hWnd, (HMENU)IDC_TRIANGLE_BUTTON, hInst, NULL);
			SendMessage(surface,BM_SETCHECK,BST_CHECKED,NULL);

			CreateWindowEx(	0, L"STATIC", L"Plane Plot Limits:", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 320, 350, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			
			CreateWindowEx(	0, L"STATIC", L"X1 = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 350, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			planeX1 = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"-2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+145, 350, 100, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"X2 = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+45+100, 350, 22, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			planeX2 = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100, 350, 100, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);

			CreateWindowEx(	0, L"STATIC", L"Y1 = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 380, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			planeY1 = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"-2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+145, 380, 100, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"Y2 = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+45+100, 380, 22, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			planeY2 = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100, 380, 100, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			
			CreateWindowEx(	0, L"STATIC", L"Z1 = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 410, 20, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			planeZ1 = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"-2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+145, 410, 100, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);
			CreateWindowEx(	0, L"STATIC", L"Z2 = ", WS_CHILD|WS_VISIBLE, rcClient.right/2+120+45+100, 410, 22, 20, hWnd, (HMENU)IDC_EQ_LABEL, hInst, NULL);
			planeZ2 = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"2.0", WS_CHILD|WS_VISIBLE, rcClient.right/2+2+145+45+100, 410, 100, 20, hWnd, (HMENU)IDC_EDIT_EQ, hInst, NULL);

			CreateWindowEx( 0, L"BUTTON", L"Orthographic", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 440, 120, 30, hWnd, (HMENU)IDC_ORTHOGRAPHIC_BUTTON, hInst, NULL);
			CreateWindowEx( 0, L"BUTTON", L"Perspective",  WS_CHILD|WS_VISIBLE, rcClient.right/2+120+140, 440, 120, 30, hWnd, (HMENU)IDC_PERSPECTIVE_BUTTON, hInst, NULL);
			
			plot = CreateWindowEx( 0, L"BUTTON", L"Plot", WS_CHILD|WS_VISIBLE, rcClient.right/2+120, 490, 120, 30, hWnd, (HMENU)IDC_PLOT_BUTTON, hInst, NULL);
		}break;

		case WM_DESTROY:
		{
			PostQuitMessage(0);
		}break;

		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return DefWindowProc(hWnd, message, wParam, lParam); 
}


// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
		case WM_INITDIALOG:
		{
			return (INT_PTR)TRUE;
		}break;

		case WM_COMMAND:
		{
			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
			{
				EndDialog(hDlg, LOWORD(wParam));
				return (INT_PTR)TRUE;
			}
		}break;
	}
	return (INT_PTR)FALSE;
}

void CreateObjects()
{
	if( g_Surface[0] )
		delete g_Surface[0];
	if( g_Surface[1] )
		delete g_Surface[1];
	if( g_PlaneXY )
		delete g_PlaneXY;
	if( g_PlaneXZ )
		delete g_PlaneXZ;
	if( g_PlaneYZ )
		delete g_PlaneYZ;

	g_Surface[0] = new CSurface( D3DXVECTOR3(			phiA,	thetaA,  0.0 ),
								 D3DXVECTOR3(	phiB*D3DX_PI,   thetaA,  0.0 ),
								 D3DXVECTOR3(			phiA,	thetaB*D3DX_PI,  0.0 ),
								 D3DXVECTOR3(	phiB*D3DX_PI,	thetaB*D3DX_PI,  0.0 ));
	
	g_Surface[1] = new CSurface( D3DXVECTOR3(         phiA,	        thetaA,  0.0 ),
								 D3DXVECTOR3( phiB*D3DX_PI,         thetaA,  0.0 ),
								 D3DXVECTOR3( 		  phiA,	thetaB*D3DX_PI,  0.0 ),
								 D3DXVECTOR3( phiB*D3DX_PI,	thetaB*D3DX_PI,  0.0 ));

	g_Surface[1]->m_wire = true;
	/*
	g_PlaneXY =  new CSurface( D3DXVECTOR3(	-2.0, -2.0,  0.0 ),
							   D3DXVECTOR3(  2.0, -2.0,  0.0 ),
							   D3DXVECTOR3( -2.0,  2.0,  0.0 ),
							   D3DXVECTOR3(  2.0,  2.0,  0.0 ));
	
	g_PlaneXZ =  new CSurface( D3DXVECTOR3(	-2.0,  0.0, -2.0 ),
							   D3DXVECTOR3(  2.0,  0.0, -2.0 ),
							   D3DXVECTOR3( -2.0,  0.0,  2.0 ),
							   D3DXVECTOR3(  2.0,  0.0,  2.0 ));
	
	g_PlaneYZ =  new CSurface( D3DXVECTOR3(	0.0, -2.0, -2.0 ),
							   D3DXVECTOR3( 0.0,  2.0, -2.0 ),
							   D3DXVECTOR3( 0.0, -2.0,  2.0 ),
							   D3DXVECTOR3( 0.0,  2.0,  2.0 ));
	*/
	g_PlaneXY =  new CSurface( D3DXVECTOR3(	 plX1,  plY1,  0.0 ),
							   D3DXVECTOR3(  plX2,  plY1,  0.0 ),
							   D3DXVECTOR3(  plX1,  plY2,  0.0 ),
							   D3DXVECTOR3(  plX2,  plY2,  0.0 ));
	
	g_PlaneXZ =  new CSurface( D3DXVECTOR3(	 plX1,   0.0,  plZ1 ),
							   D3DXVECTOR3(  plX2,   0.0,  plZ1 ),
							   D3DXVECTOR3(  plX1,   0.0,  plZ2 ),
							   D3DXVECTOR3(  plX2,   0.0,  plZ2 ));
	
	g_PlaneYZ =  new CSurface( D3DXVECTOR3(	  0.0,  plY1,  plZ1 ),
							   D3DXVECTOR3(   0.0,  plY2,  plZ1 ),
							   D3DXVECTOR3(   0.0,  plY1,  plZ2 ),
							   D3DXVECTOR3(   0.0,  plY2,  plZ2 ));

	g_PlaneXY->m_wire=true;
	g_PlaneXZ->m_wire=true;
	g_PlaneYZ->m_wire=true;

	g_PlaneXY->m_CullNone=true;
	g_PlaneXZ->m_CullNone=true;
	g_PlaneYZ->m_CullNone=true;
	g_PlaneXY->m_Texture=true;
	//g_PlaneXZ->m_Texture=true;
	//g_PlaneYZ->m_Texture=true;
}

void ResetView()
{
	g_Surface[0]->ResetMatrices();
	g_Surface[1]->ResetMatrices();

	g_PlaneXY->ResetMatrices();
	g_PlaneXZ->ResetMatrices();
	g_PlaneYZ->ResetMatrices();
	g_PlaneXY->ResetMatrices();
	g_PlaneXZ->ResetMatrices();
	g_PlaneYZ->ResetMatrices();
}
//---------------------------------------------------------------------------
BOOL InitDevice(HWND hWnd)
{
	RECT rect;
	GetClientRect(hWnd, &rect);
	BOOL result = TRUE;
	CGraphicsLayer::Create(hWnd,rect.right - rect.left,rect.bottom - rect.top);
	if(Graphics()==NULL){return FALSE;}

	CreateObjects();

	return (result);
}


//---------------------------------------------------------------------------
void ImageCapture(HWND hWnd)
{
	HRESULT hr;
	hr=D3DX11SaveTextureToFile(Graphics()->GetDeviceContext(),Graphics()->GetBackBuffer(),D3DX11_IFF_BMP,L".\\CapturedImg.bmp");
}

void Render()
{
	if(!Graphics()){return;}
	Graphics()->ClearBackBuffer();
	Graphics()->ClearStencilBuffer();

	if( drawSolid )
	{
		if( surfaceNormals )
			g_Surface[0]->DrawSmooth(1);
		else
			g_Surface[0]->DrawSmooth(5);
	}
	if( drawGrass )
	{
		if( surfaceNormals )
			g_Surface[0]->DrawSmooth(2);
		else
			g_Surface[0]->DrawSmooth(6);
	}

	g_PlaneXY->DrawSmooth(3);
	g_PlaneXZ->DrawSmooth(3);
	g_PlaneYZ->DrawSmooth(3);

	if( drawWire )
	{
		Graphics()->ClearStencilBuffer();
		g_Surface[1]->DrawSmooth(4);
	}

	Graphics()->Present();
}
